﻿namespace Hippo.Common.Extensions
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;

    public static class StringExtensions
    {
        /// <summary>
        /// If we only allow complete words the right edge might be a bit ugly.
        /// Instead we accept that words are broken if cut has right egde would
        /// move more than MaxStringSplitOffset characters for the cut to exist.
        /// </summary>
        private const int MaxStringSplitOffset = 6;

        /// <summary>
        /// Splits a string on whole words.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <param name="partitionSize">Size of the partition.</param>
        /// <returns>An array of strings not exceeding the partition size</returns>
        public static string[] SplitOnWholeWords(this string input, int partitionSize)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }
            if (partitionSize <= 0)
            {
                throw new ArgumentOutOfRangeException("partitionSize", "partitionSize must be larger than 0");
            }
            Contract.EndContractBlock();

            var partitioned = new List<string>();

            var rest = input;
            while (rest.Length > partitionSize)
            {
                var part = rest.Substring(0, partitionSize);
                var cutIndex = part.LastIndexOf(' ');

                /* For those cases where next character is ' ' */
                if (rest[partitionSize] == ' ')
                {
                    cutIndex = partitionSize;
                }   

                /* No space found */
                if (cutIndex == -1)
                {
                    rest = rest.Substring(partitionSize);
                }
                else if (cutIndex < partitionSize - MaxStringSplitOffset)
                {
                    const int PushCharactersToNextRow = 2;

                    /* Remove add a dash to the end of the string */
                    part = part.Substring(0, part.Length - PushCharactersToNextRow) + "-";

                    /* Remove part from the rest */
                    rest = rest.Substring(part.Length - 1);
                }
                else
                {
                    /* Refine cut */
                    part = part.Substring(0, cutIndex);

                    /* Remove part from the rest (including the space) */
                    rest = rest.Substring(cutIndex + 1);
                }

                partitioned.Add(part);
            }

            partitioned.Add(rest);
            return partitioned.ToArray();
        }
    }
}
